#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "typedefs.h"
#include "hal.h"

#define HAL_AFE_RNDNUMGEN_MULT 31821 	// multiplier value (last 3 digits are even-2-1)
#define HAL_AFE_RNDNUMGEN_INC  13849 		// 1 and 13849 have been tested

UINT16 HAL_afe_rndNumGen_init_seed =1 ;

extern SINT16 txSymbFlag;                 

HAL_afe_handle_t HAL_afe_handle_s;
HAL_afe_epwm_handle_t HAL_afe_epwm_handle_s;

HAL_status_t (*HAL_afe_set[NUM_AFE_SETPARMS])(void *setParms_s) =
{
  HAL_afe_txCfg,  		//AFE_TX_CFG
  HAL_afe_txStart,		//AFE_TX_START
  HAL_afe_txStop,		//AFE_TX_STOP
  HAL_afe_txReCfg,		//AFE_TX_RECFG
  HAL_afe_txDmaSize,	//AFE_TX_DMASIZE
  HAL_afe_txDmaAddr,	//AFE_TX_DMAADDR
  
  HAL_cpuTimer0TimeoutCfg,  //AFE_TX_T0CFG
  HAL_cpuTimer0Start,		//AFE_TX_T0START
  HAL_cpuTimer0Stop,		//AFE_TX_T0STOP

  HAL_afe_rxStart,		//AFE_RX_START
  HAL_afe_rxStop,		//AFE_RX_STOP
  HAL_afe_rxReCfg,		//AFE_RX_RECFG
  HAL_afe_setGain,		//AFE_RX_SETGAIN
  HAL_afe_updateGain,	//AFE_RX_UPDATEGAIN
  HAL_afe_cancelGain,	//AFE_RX_CANCEL_GAIN
};

HAL_status_t (*HAL_afe_get[NUM_AFE_GETPARMS])(void *getParms_s) =
{
  HAL_afe_rxDmaTime,	//AFE_RX_DMATIME
  HAL_afe_zcTime,		//AFE_ZCTIME
  HAL_afe_rxDmaIdx,		//AFE_RX_DMAIDX
  HAL_afe_rndNum,		//AFE_RND_NUM
  HAL_afe_rxBufPtrSz
};

HAL_afe_txSetParms_t HAL_afe_txSetParms_s;


/******************************************************************************
* FUNCTION NAME: HAL_afe_prfCfg
*
* DESCRIPTION:   AFE Profiles
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_prfCfg(void *setParms_p)
{
	HAL_afe_prfParms_t *HAL_afe_prfParms_p = (HAL_afe_prfParms_t *)setParms_p;

	HAL_afe_handle_s.prf.rx_fs_kHz = HAL_afe_prfParms_p->rx_fs_kHz;
	HAL_afe_handle_s.prf.tx_fs_kHz = HAL_afe_prfParms_p->tx_fs_kHz;
	HAL_afe_handle_s.prf.tx_pwm_kHz = HAL_afe_prfParms_p->tx_pwm_kHz;
	HAL_afe_handle_s.prf.band = HAL_afe_prfParms_p->band;

	/* T0 period in us (Q1) */
	HAL_afe_handle_s.t0Prd = (1000 << 1) / HAL_afe_prfParms_p->tx_fs_kHz;

	/* SOC is always from symmetric PWM */
	HAL_afe_epwm_handle_s.socPrd = (Uint16)(60000 / HAL_afe_prfParms_p->rx_fs_kHz)*2;  //for PWM triggered ADC

	/* TX triggered by asymmetric PWM */
	HAL_afe_epwm_handle_s.txPrd = (Uint16)60000 / HAL_afe_prfParms_p->tx_fs_kHz - 1; // for TX HRPWM

	/* TX HRPWM maybe symmetric or asymmetric */
	HAL_afe_epwm_handle_s.prd = (Uint16)60000 / HAL_afe_prfParms_p->tx_pwm_kHz / 2; // for TX HRPWM

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afeRxInit
*
* DESCRIPTION:   AFE RX init function.
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afeRxInit(void)
{
	HAL_afe_handle_s.updateGainFlag = 0;
	HAL_afe_handle_s.agcGainVal = 0;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afeTxInit()
*
* DESCRIPTION:   AFE TX init function.
*
* Return Value:  None
*
* Input Parameters: bios - 0-no bios; 1-bios
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afeTxInit(void)
{
	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afeInit()
*
* DESCRIPTION:   AFE init function.
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afeInit(HAL_afe_prfParms_t *setParms_p)
{
	memset(&HAL_afe_handle_s, 0, sizeof(HAL_afe_handle_t));

	HAL_afe_prfCfg((void *)setParms_p);

	HAL_afeRxInit();

	HAL_afeTxInit();

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_rxStart
*
* DESCRIPTION:   RX start.
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_rxStart(void *setParms_p)
{
	HAL_afe_rxSetParms_t *HAL_afe_rxSetParms_p = (HAL_afe_rxSetParms_t *)setParms_p;

	Uint16 dstBufIdx = HAL_afe_rxSetParms_p->dstBufIdx;
	Uint16 dstNextBufIdx = (dstBufIdx + 1)&1;

	HAL_afe_handle_s.rxBufIdx = dstNextBufIdx; 
	HAL_afe_handle_s.rxBufPtr_p[dstBufIdx] = HAL_afe_rxSetParms_p->dstBufAddr[dstBufIdx];
	HAL_afe_handle_s.rxBufPtr_p[dstNextBufIdx] = HAL_afe_rxSetParms_p->dstBufAddr[dstNextBufIdx];
	HAL_afe_handle_s.rxBufSize[dstBufIdx] = HAL_afe_rxSetParms_p->size[dstBufIdx];
	HAL_afe_handle_s.rxBufSize[dstNextBufIdx] = HAL_afe_rxSetParms_p->size[dstNextBufIdx];
	HAL_afe_handle_s.rxBufDat_p = HAL_afe_handle_s.rxBufPtr_p[dstBufIdx];

	HAL_afe_handle_s.activeBufIdx = dstBufIdx;
	HAL_afe_handle_s.activeBufSize = HAL_afe_rxSetParms_p->size[dstBufIdx];
	HAL_afe_handle_s.adcCnt = 0;

	PLC_print("[HAL_afe_rxStart]: dstBufIdx = %d, 0x%x, 0x%x\n", dstBufIdx, HAL_afe_handle_s.rxBufPtr_p[dstBufIdx], HAL_afe_handle_s.rxBufPtr_p[dstNextBufIdx]);
	PLC_print("[HAL_afe_rxStart]: rxBufSize = 0x%x, 0x%x, 0x%x\n", HAL_afe_handle_s.rxBufDat_p, HAL_afe_handle_s.rxBufSize[dstBufIdx], HAL_afe_handle_s.rxBufSize[dstNextBufIdx]);
	PLC_print("[HAL_afe_rxStart]: activeBufIdx = %d, %d\n", HAL_afe_handle_s.activeBufIdx, HAL_afe_handle_s.activeBufSize);

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_rxStop
*
* DESCRIPTION:   RX stop
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_rxStop(void *setParms_p)
{
	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_rxReCfg
*
* DESCRIPTION:   RX re-configure
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_rxReCfg(void *setParms_p)
{
	HAL_afe_rxSetParms_t *HAL_afe_rxSetParms_p = (HAL_afe_rxSetParms_t *)setParms_p;

	Uint16 dstBufIdx = HAL_afe_rxSetParms_p->dstBufIdx;
	Uint16 dstNextBufIdx = (dstBufIdx + 1)&1;

	HAL_afe_handle_s.rxBufIdx = dstBufIdx;
	HAL_afe_handle_s.rxBufPtr_p[dstBufIdx] = HAL_afe_rxSetParms_p->dstBufAddr[dstBufIdx];
	HAL_afe_handle_s.rxBufPtr_p[dstNextBufIdx] = HAL_afe_rxSetParms_p->dstBufAddr[dstNextBufIdx];
	HAL_afe_handle_s.rxBufSize[dstBufIdx] = HAL_afe_rxSetParms_p->size[dstBufIdx];
	HAL_afe_handle_s.rxBufSize[dstNextBufIdx] = HAL_afe_rxSetParms_p->size[dstNextBufIdx];
	
	PLC_print("[HAL_afe_rxReCfg]: dstBufIdx = %d, %d, 0x%x\n", dstBufIdx,  HAL_afe_handle_s.rxBufSize[dstBufIdx], HAL_afe_handle_s.rxBufPtr_p[dstBufIdx]);
	PLC_print("[HAL_afe_rxReCfg]: dstNextBufIdx = %d, %d, 0x%x\n", dstNextBufIdx,HAL_afe_handle_s.rxBufSize[dstNextBufIdx], HAL_afe_handle_s.rxBufPtr_p[dstNextBufIdx]);

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_txCfg
*
* DESCRIPTION:   TX configure.
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_txCfg(void *setParms_s)
{
	HAL_afe_txSetParms_t *txSetParms_s = (HAL_afe_txSetParms_t *)setParms_s;

	HAL_afe_handle_s.txBufReady_p = (Uint16 *)txSetParms_s->txBuf_p;
	HAL_afe_handle_s.bufDat_p = (Uint16 *)txSetParms_s->txBuf_p;

	HAL_afe_handle_s.txSize = txSetParms_s->txSize;
	HAL_afe_handle_s.txBufSize = txSetParms_s->txSize;
	HAL_afe_handle_s.txBufIdx = 0;

	PLC_print("[HAL_afe_txCfg]: txBufReady_p = 0x%x\n", HAL_afe_handle_s.txBufReady_p);
	PLC_print("[HAL_afe_txCfg]: bufDat_p = 0x%x\n", HAL_afe_handle_s.bufDat_p);
	PLC_print("[HAL_afe_txCfg]: txSize = 0x%x\n", HAL_afe_handle_s.txSize);
	PLC_print("[HAL_afe_txCfg]: txBufSize = 0x%x\n", HAL_afe_handle_s.txBufSize);
	PLC_print("[HAL_afe_txCfg]: txBufIdx = 0x%x\n", HAL_afe_handle_s.txBufIdx);

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_txReCfg
*
* DESCRIPTION:   TX re-configure.(TX size)
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_txReCfg(void *setParms_s)
{
	HAL_afe_txSetParms_t *txSetParms_s = (HAL_afe_txSetParms_t *)setParms_s;

	HAL_afe_handle_s.txBufReady_p = (Uint16 *)txSetParms_s->txBuf_p;
	HAL_afe_handle_s.txSize = txSetParms_s->txSize;

	PLC_print("[HAL_afe_txReCfg]: txBufReady_p = 0x%x\n", HAL_afe_handle_s.txBufReady_p);
	PLC_print("[HAL_afe_txReCfg]: txSize = 0x%x\n", HAL_afe_handle_s.txSize);

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_txStart
*
* DESCRIPTION:   TX start. Depend on how TX is disabled.
*                For now does two tasks:
*                (1) Start CPU timer (@ TX sampling rate)
*                (2) Enable PWM TBCLK
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_txStart(void *setParms_p)
{
	HAL_afe_handle_s.bufDat_p = HAL_afe_handle_s.txBufReady_p;

	HAL_afe_handle_s.txActive = 1;

	PLC_print("[HAL_afe_txStart]: bufDat_p = 0x%x\n", HAL_afe_handle_s.bufDat_p);

	txSymbFlag = 1;                 

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_txStop
*
* DESCRIPTION:   TX Disable.
*                For now does two tasks:
*                (1) Stop CPU timer (@ TX sampling rate)
*                (2) Disable PWM TBCLK
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_txStop(void *setParms_p)
{
	HAL_afe_handle_s.txActive = 0;

	txSymbFlag = 0;                 

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_txDmaSize
*
* DESCRIPTION:   Set TX DMA size.
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_txDmaSize(void *setParms)
{
	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_txDmaAddr
*
* DESCRIPTION:   Set TX DMA src address.
*
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_txDmaAddr(void *setParms)
{
	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_setGain
*
* DESCRIPTION:   Set AFE PGA gain through SPI
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_setGain(void *setParms_p)
{
	Uint16 *gain = (Uint16 *)setParms_p;

	HAL_afe_handle_s.agcGainVal = *gain;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_updateGain
*
* DESCRIPTION:   Set AFE PGA gain through SPI at CP
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_updateGain(void *setParms_p)
{
	Uint16 *gain = (Uint16 *)setParms_p;

	HAL_afe_handle_s.agcGainVal = *gain;
	HAL_afe_handle_s.updateGainFlag = 1;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_cancelGain
*
* DESCRIPTION:   Cancel gain update
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afe_cancelGain(void *setParms_p)
{
	HAL_afe_handle_s.updateGainFlag = 0;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_cpuTimerCfg
*
* DESCRIPTION:   Configure CPU timer to TX sampling rate (500kHz).
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*                  InitCpuTimers (from TI header lib)
*                  ConfigVpuTimer (from TI header lib)
******************************************************************************/
HAL_status_t HAL_cpuTimerCfg()
{
	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_cpuTimer1CfgStart
*
* DESCRIPTION:   Configure and start CPU timer1
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
******************************************************************************/
HAL_status_t HAL_cpuTimer1CfgStart()
{
	txSymbFlag = 1;

	return HAL_STAT_SUCCESS;
}

Uint32 HAL_cpuTimer1GetCount(void)
{
	return 10;
}

/******************************************************************************
* FUNCTION NAME: HAL_cpuTimer0TimeoutCfg
*
* DESCRIPTION:   Configure CPU timer0 timeout
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
******************************************************************************/
HAL_status_t HAL_cpuTimer0TimeoutCfg(void *setParms)
{
	HAL_afe_txSetParms_t *txSetParms_s = (HAL_afe_txSetParms_t *)setParms;

	HAL_afe_handle_s.timer01ShotFlag = (txSetParms_s->t0Flags & HAL_AFE_TIMER_1_SHOT) >> 1;

	HAL_afe_handle_s.cb_p = txSetParms_s->cb_p;
	HAL_afe_handle_s.cb_param = txSetParms_s->cb_param;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_cpuTimer0Start
*
* DESCRIPTION:   CPU timer0 start.
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_cpuTimer0Start(void *getParms)
{
	txSymbFlag = 1;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_cpuTimer0Stop
*
* DESCRIPTION:   CPU timer0 stop.
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_cpuTimer0Stop(void *getParms)
{
	txSymbFlag = 0;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_rxDmaTime
*
* DESCRIPTION:   Get RX DMA time
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
******************************************************************************/
HAL_status_t HAL_afe_rxDmaTime(void *getParms)
{
	Uint32 *val_p = (Uint32 *)getParms;

	*val_p = HAL_afe_handle_s.rxDmaTime;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_zcTime
*
* DESCRIPTION:   Get ZC time
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
******************************************************************************/
HAL_status_t HAL_afe_zcTime(void *getParms)
{
	HAL_afe_zcTime_t *val_p = (HAL_afe_zcTime_t *)getParms;

	val_p->zcaTime = HAL_afe_handle_s.zcaTime;
	val_p->zcbTime = HAL_afe_handle_s.zcbTime;
	val_p->zcaPeriod = HAL_afe_handle_s.zcaPeriod;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_rxDmaIdx
*
* DESCRIPTION:   Get DMA buffer index
*
* Return Value:  DMA buffer index
*
* Input Parameters:
*                NONE
*
* Output Parameters:
* Functions Called:
*                NONE
******************************************************************************/
HAL_status_t HAL_afe_rxDmaIdx(void *getParms)
{
	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_afe_rndNum
*
* DESCRIPTION:   Get a random number from ADC
*
* Return Value:  Random number
*
* Input Parameters:
*                NONE
*
* Output Parameters:
* Functions Called:
*                NONE
******************************************************************************/
HAL_status_t HAL_afe_rndNum(void *getParms)
{
	Uint16 *data_p;
	UINT16 random_number = 1;

	// On first call to the function, modify the initial seed
	// based on some ADC samples
	if (HAL_afe_rndNumGen_init_seed == 1)
	{
		Uint16 idx;

		data_p = (Uint16 *)HAL_afe_handle_s.rxBufPtr_p[HAL_afe_handle_s.rxBufIdx];

		for (idx = 0; idx < 16; idx++)
		{
			random_number |= (*data_p++ & 0x01)<<idx;
		}

		random_number = random_number * HAL_AFE_RNDNUMGEN_MULT + HAL_AFE_RNDNUMGEN_INC;

		HAL_afe_rndNumGen_init_seed = 0;
	}

	random_number = random_number * HAL_AFE_RNDNUMGEN_MULT + HAL_AFE_RNDNUMGEN_INC;

	data_p = (UINT16 *)getParms;
	*data_p = random_number;

	return HAL_STAT_SUCCESS;
}


/******************************************************************************
* FUNCTION NAME: HAL_afe_rxBufPtrSz
*
* DESCRIPTION:   Get RX Buffer pointer & size
*
* Return Value:  Data Pointer to the (last element of the previous buffer)+1, or first of the next;
*                Previous active buffer size
*
* Input Parameters:
*                NONE
*
* Output Parameters:
* Functions Called:
*                NONE
******************************************************************************/
HAL_status_t HAL_afe_rxBufPtrSz(void *getParms)
{
	HAL_afe_rxBufPtrSz_t *val_p = (HAL_afe_rxBufPtrSz_t *)getParms;

	val_p->buf_p = (UINT16 *)HAL_afe_handle_s.rxBufDatPrvFld_p;
	val_p->size = (UINT16)HAL_afe_handle_s.rxBufSizePrvFld;

	return HAL_STAT_SUCCESS;
}

/******************************************************************************
* FUNCTION NAME: HAL_cfgCpuTimer0
*
* DESCRIPTION:   CPU timer0 interrupt service routine function.
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
void  HAL_cfgCpuTimer0(UINT16 cpu_frez_MHz, UINT16 fs_kHz)
{
	txSymbFlag = 0;
}

/******************************************************************************
* FUNCTION NAME: HAL_afeSet
*
* DESCRIPTION:   AFE set function.
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afeSet(HAL_afe_setCode_t setCode, void *setParms_p)
{
	return (*HAL_afe_set[setCode])(setParms_p);
}

/******************************************************************************
* FUNCTION NAME: HAL_afeGet
*
* DESCRIPTION:   AFE get function.
*
* Return Value:  None
*
* Input Parameters:
*
* Output Parameters:
* Functions Called:
*
******************************************************************************/
HAL_status_t HAL_afeGet(HAL_afe_getCode_t getCode, void *getParms_p)
{
	return (*HAL_afe_get[getCode])(getParms_p);
}
